/* eslint-disable no-unused-vars */
/* eslint-disable no-param-reassign */
/* eslint-disable import/no-cycle */
import React from 'react';
import DesignUtil from '../common/DesignUtil';
import ControlPlus from './ControlPlus';

class ControlUtil {
  //
  // 控件排序刷新算法
  // 用于兼容旧表单控件，根据实际表单设计的位置规则，刷新表单实际存储位置
  //
  static refreashOrder(controls) {
    // console.log(`排序前`, controls);
    // 根据实际排序位置刷新order
    controls.forEach((item, index) => {
      item.data.order = index + 1;
    });
    // 根据order排序当前控件,理论上位置不变
    controls = controls.sort((a, b) => {
      return a.data.order - b.data.order;
    });
    // 刷新子控件order
    controls.forEach((item, index) => {
      if (item.data.childControls != null) {
        item.data.childControls = this.refreashOrder(item.data.childControls);
      }
    });
    // console.log(`排序后`, controls);
    return controls;
  }

  //
  // 控件排序回复算法
  // 用于兼容旧表单控件，根据实际表单设计的位置规则，刷新表单显示位置
  //
  static loadOrder(controls) {
    controls = controls.sort((a, b) => {
      return a.data.order - b.data.order;
    });
    // 根据实际排序位置刷新order
    controls.forEach((item, index) => {
      if (item.data.childControls != null) {
        item.data.childControls = this.loadOrder(item.data.childControls);
      }
    });
    return controls;
  }

  // 加载form表单算法2：新旧表单差异合并算法
  static loadForm2(children, controlJson) {
    // 旧表单元素结构
    const oldControlsSource = ControlUtil.getOldFormControls(children, null);
    // 旧元素重复检测并移除
    const oldControls = ControlUtil.checkAdnfilterControlsKeyRepeat(oldControlsSource, new Map());
    // 旧元素map结构
    const controlmapref = new Map();
    ControlUtil.controlsToMap(oldControls, controlmapref);
    // 合并新旧表单
    const newControls = ControlUtil.getFormControls(controlJson, controlmapref);
    // 增加未包含的结构
    ControlUtil.loadNewOldFormControls(controlmapref, newControls);
    // 全局排序
    const orderControls = ControlUtil.loadOrder(newControls);
    return orderControls;
  }

  // 旧表单元素结构
  static getOldFormControls(children, parentControl) {
    const results = [];
    React.Children.forEach(children || [], (child, index) => {
      const old = ControlPlus.createByOldFormChild(child, index + 1);
      old.temp = { parent: parentControl?.data.key || null };
      results.push(old);
      if (old.data.childControls != null) {
        old.data.childControls = ControlUtil.getOldFormControls(child.props.children, old);
      }
    });
    return results;
  }

  // 加载新表单元素
  static getFormControls(controlsJson, controlmapref) {
    const results = [];
    // 合并新旧表单,差异合并算法
    controlsJson.forEach((c) => {
      if (c.childControls != null) {
        c.childControls = ControlUtil.getFormControls(c.childControls, controlmapref);
      }
      if (controlmapref.has(c.key)) {
        const find = controlmapref.get(c.key);
        find.load(c); // 旧元素配置
        controlmapref.delete(c.key);
        results.push(find);
      } else {
        // if (c.custom === true) {
        const t = ControlPlus.create(c.type);
        t.load(c); // 新元素添加
        results.push(t);
      }
    });
    return results;
  }

  // 加载新添的旧表单元素
  static loadNewOldFormControls(controlmapref, controls) {
    controlmapref.forEach(function (value, key) {
      const c = ControlUtil.deepFindControl(controls, key);
      if (c == null) {
        const parent = value.temp.parent;
        if (parent == null) {
          controls.push(value);
          controlmapref.delete(key);
        } else {
          const find = ControlUtil.deepFindControl(controls, parent);
          if (find != null) {
            find.data.childControls.push(value);
            controlmapref.delete(key);
          } else {
            console.error('新增的旧表单元素无法显示');
          }
        }
      } else {
        controlmapref.delete(key);
      }
    });
  }

  // 控件渲染
  static controlsRender(controls, parentForm) {
    return controls.map((item, index) => {
      return item.render(parentForm);
    });
  }

  // controls结构转map结构
  static controlsToMap(controls, controlmapref) {
    controls.forEach((c) => {
      if (controlmapref.has(c.data.key)) {
        console.warn(`检测到designkey重复:${c.data.key}`);
      }
      controlmapref.set(c.data.key, c);
      if (c.data.childControls != null) {
        ControlUtil.controlsToMap(c.data.childControls, controlmapref);
      }
    });
  }

  // controls结构检测重复并移除
  static checkAdnfilterControlsKeyRepeat(controls, controlmapref) {
    const results = [];
    controls.forEach((c) => {
      if (controlmapref.has(c.data.key)) {
        console.warn(`检测到designkey重复:${c.data.key},已移除渲染`);
      } else {
        results.push(c);
        controlmapref.set(c.data.key, c);
        if (c.data.childControls != null) {
          c.data.childControls = ControlUtil.checkAdnfilterControlsKeyRepeat(c.data.childControls, controlmapref);
        }
      }
    });
    return results;
  }

  // 查找控件,深度遍历，性能不高
  static deepFindControl(controls, key) {
    let find = null;
    ControlUtil.deepSearchControls(controls, null, (item, parent, index, end) => {
      if (item != null && item.data.key === key) {
        find = item;
        return false;
      }
      return true;
    });
    return find;
  }

  // 删除控件,深度遍历，性能不高
  static deepRemoveControl(controls, key) {
    const tempControls = ControlUtil.deepMapControls(controls, null, (item, parent, index, end) => {
      if (item != null && item.data.key === key) {
        return null;
      }
      return item;
    });
    return tempControls;
  }

  // 用以查找当前鼠标位置（point）所在的控件index
  static movePointControl(controls, point, from, parentForm) {
    //   //手势判断
    //   const direction = DesignUtil.getDirection(from.startPoint.x,from.startPoint.y,point.x,point.y);
    // 查找
    let formControl = null;
    if (from.key != null) {
      formControl = ControlUtil.deepFindControl(controls, from.key);
    } else {
      const c = ControlPlus.create(from.type);
      c.data.custom = true;
      c.init(parentForm);
      formControl = c;
    }
    // 移除
    const tempControls = ControlUtil.deepRemoveControl(controls, formControl.data.key);
    // 插入
    let insert = false;
    const tempControls2 = ControlUtil.deepMapControls(tempControls, null, (item, parent, index, end) => {
      if (insert === false) {
        // 容器内部
        if (parent != null && DesignUtil.isInSize(point, parent.getClientRect())) {
          // 在父容器的子容器中，则跳过
          if (ControlUtil.isInChildContainer(parent, point)) {
            return item;
          }
          // 在当前容器中,则排序
          if (parent.data.canAddChild === true) {
            const rs = ControlUtil.insertControlToPointWithNoParent(item, point, formControl, end);
            if (rs != null) {
              insert = true;
              return rs;
            }
          }
        }
        // 无容器（第一层）
        if (parent == null) {
          const rs = ControlUtil.insertControlToPointWithNoParent(item, point, formControl, end);
          if (rs != null) {
            insert = true;
            return rs;
          }
        }
      }
      return item;
    });
    parentForm.refreshControlsOrder(tempControls2);
  }

  // 是否在子容器内
  static isInChildContainer(item, point) {
    if (item != null && DesignUtil.isInSize(point, item.getClientRect()) && item.data.childControls != null) {
      const childControls = item.data.childControls;
      if (childControls != null) {
        let hasContainerInSize = false; // 检查是否有更小容器
        childControls.forEach((c) => {
          if (c != null && DesignUtil.isInSize(point, c.getClientRect()) && c.data.canAddChild === true) {
            hasContainerInSize = true;
          }
        });
        if (hasContainerInSize === true) {
          return true;
        }
      }
    }
    return false;
  }

  static insertControlToPointWithNoParent(item, point, formControl, end) {
    // 第一个
    if (item == null) {
      return formControl;
    }
    // 插入当前位置
    if (DesignUtil.isLeftTopOfSize(point, item.getClientRect())) {
      return [formControl, item];
    }
    // 最后一个(非容器)
    if (end === true) {
      // 当前容器中，则跳过
      if (
        DesignUtil.isInSize(point, item.getClientRect()) &&
        item.data.childControls != null &&
        item.data.canAddChild === true
      ) {
        return null;
      }
      // 当前的子容器中,则跳过
      if (ControlUtil.isInChildContainer(item, point)) {
        return null;
      }
      return [item, formControl];
    }
    return null;
  }

  // 深度优先map
  static deepMapControls(controls, parentControl, callback, startIndex) {
    const start = startIndex || 0;
    const results = [];
    const length = controls.length;
    // 容器为空的情况下，作为父节点增加一次遍历
    if (length === 0) {
      const re = callback && callback(null, parentControl, start, true);
      if (re == null) {
        // do noting
      } else if (Array.isArray(re)) {
        re.forEach((r) => {
          results.push(r);
        });
      } else {
        results.push(re); // 支持array
      }
    } else {
      controls.forEach((c, index) => {
        const indexNow = start + index;
        const end = index + 1 === length; // 最后一个
        const re = callback && callback(c, parentControl, indexNow, end);
        if (re == null) {
          // do noting
        } else if (Array.isArray(re)) {
          re.forEach((r) => {
            results.push(r);
          });
        } else {
          results.push(re); // 支持array
        }

        if (c.data.childControls != null) {
          c.data.childControls = ControlUtil.deepMapControls(c.data.childControls, c, callback, indexNow);
        }
      });
    }
    return results;
  }

  // 深度优先查找
  static deepSearchControls(controls, parentControl, callback, startIndex) {
    try {
      const start = startIndex || 0;
      const length = controls.length;
      // 容器为空的情况下，作为父节点增加一次遍历
      controls.forEach((c, index) => {
        const indexNow = start + index;
        const end = index + 1 === length; // 最后一个
        const re = callback && callback(c, parentControl, indexNow, end);
        if (re === false) {
          throw new Error('StOPLOOP');
        }
        if (c.data.childControls != null) {
          ControlUtil.deepSearchControls(c.data.childControls, c, callback, indexNow);
        }
      });
    } catch (e) {
      if (e.message !== 'StOPLOOP') throw e;
    }
  }
}
export default ControlUtil;
